﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MutFormStudio {
	public partial class Studio : UserControl,IEnumerable<StudioFormHead>,IEnumerable<Studio> {
		Control mainControl = null;
		public Control MainControl { get =>
				mainControl; 
			set {
				mainControl = value;
				if (Is_leaf) { 
					Tab_studio.Owner = this;
				}
			}
		}


		/// <summary>拥有本工作间的基本工作间，或者本工作间就是基本工作间</summary>
		public readonly BaseStudio Base_studio;
		public bool Is_leaf => MainControl is TabStudio;
		public bool Is_spliter => MainControl is SplitContainer;
		public TabStudio Tab_studio => MainControl as TabStudio;
		public SplitContainer Splitter => MainControl as SplitContainer;

		


		/// <summary>第一个下级工作间</summary>
		public Studio Main_studio { 
			get {
				if (Is_spliter) {
					var sc = MainControl as SplitContainer;
					return (((SplitDirection, Studio, Studio))(sc.Tag)).Item2;
				}else {
					return null;
				}
			}
		}

		/// <summary>第二个下级工作间</summary>
		public Studio Second_studio {
			get {
				if (Is_spliter) {
					var sc = MainControl as SplitContainer;
					return (((SplitDirection, Studio, Studio))(sc.Tag)).Item3;
				} else {
					return null;
				}
			}
		}

		/// <summary>分割的方向</summary>
		public SplitDirection Direction {
			get {
				if (Is_spliter) {
					var sc = MainControl as SplitContainer;
					return (((SplitDirection, Studio, Studio))(sc.Tag)).Item1;
				} else {
					return SplitDirection.None;
				}
				
			}
		}






		/// <summary>
		/// 关闭studio和下辖的全部控件
		/// </summary>
		/// <returns></returns>
		internal bool closeSubControl() {
			ControlsCloseEventArgs e = new ControlsCloseEventArgs();
			e.Close_flags = (
				from f in (IEnumerable<StudioFormHead>)this
				select new ClosingControlFlag(f)
				).ToArray();
			Base_studio.onControlsClosing(e);
			if (e.Cancle_all) {//取消全部的关闭任务
				return false;
			}
			bool rev = true;
			foreach (var flag in e.Close_flags) {
				if (flag.Cancle == false) {//仅关执行许可的关闭任务
					flag.head.tag_studio.removeControl(flag.head);
					flag.head.Dispose();
					flag.dControlClosed?.Invoke(flag.Control);
				} else {//如果有不许可的关闭任务，则返回false。通常此时就不能关闭整个窗口了
					rev = false;
				}
			}
			return rev;
		}

		/// <summary>初始化为基础工作间</summary>
		public Studio() {
			Base_studio = new BaseStudio();
			InitializeComponent();
			initializeDrag();
			MainControl = createTabStudio();
			Controls.Add(MainControl);
			Base_studio.studios.Add(this);
		}
		/// <summary>初始化为子工作间</summary>
		private Studio(BaseStudio base_studio, Control c=null) {
			Base_studio = base_studio;
			InitializeComponent();
			initializeDrag();
			if (c == null) {
				c = createTabStudio();
			}
			MainControl = c;
			Controls.Add(MainControl);
		}
		/// <summary>为子窗口创建工作间，并将其加入基本工作间的studios</summary>
		private Studio createSubForm() {
			Studio to = new Studio(Base_studio);
			Base_studio.studios.Add(to);
			var form = new IndependentStudioForm(to);
			form.Show();
			return to;
		}
		#region 分裂窗口相关的功能
		/// <summary>为Studio创建Tab控件</summary>
		private TabStudio createTabStudio() {
			var ts = new TabStudio(this);
			ts.Dock = DockStyle.Fill;
			return ts;
		}

		internal void OnTabStudioEmpty(TabStudio ts) {
			if(this.Parent is IndependentStudioForm) {
				(this.Parent as IndependentStudioForm).Close();
				Base_studio.studios.Remove(this);
				this.Dispose();
			} else if(this.Parent is SplitterPanel){
				Studio s = ((Parent as SplitterPanel).Parent as SplitContainer).Parent as Studio;
				if (s.Main_studio.MainControl == ts) {
					s.unSplit(s.Main_studio);
				} else if (s.Second_studio.MainControl == ts) {
					s.unSplit(s.Second_studio);
				}
			}
		}


		/// <summary>移除本工作间拥有的某个子控件</summary>
		public void unSplit(Studio removing_studio) {
			if(Is_spliter) {
				Controls.Remove(MainControl);
				if (Main_studio == removing_studio) {
					Second_studio.Controls.Remove(Second_studio.MainControl);
					MainControl = Second_studio.MainControl;
				} else if(Second_studio == removing_studio) {
					Main_studio.Controls.Remove(Second_studio.MainControl);
					MainControl = Main_studio.MainControl;
				} else {
					throw new InvalidOperationException("本工作室不拥有要删除的工作室");
				}
				Controls.Add(MainControl);
			}
		}
		public void Split(SplitDirection sd) {
			Controls.Remove(MainControl);
			SplitContainer sc = createSplitContainer(sd, 
				new Studio(Base_studio, MainControl),
				new Studio(Base_studio));
			MainControl = sc;
			Controls.Add(MainControl);
		}

		private static SplitContainer createSplitContainer(SplitDirection sd, Studio main_stu, Studio second_stu) {
			SplitContainer sc = new SplitContainer();
			sc.Dock = DockStyle.Fill;
			sc.Tag = (sd, main_stu, second_stu);
			switch (sd) {
				case SplitDirection.Bottom:
					sc.Orientation = Orientation.Horizontal;
					sc.Panel1.Controls.Add(main_stu);
					sc.Panel2.Controls.Add(second_stu);
					break;
				case SplitDirection.Top:
					sc.Orientation = Orientation.Horizontal;
					sc.Panel2.Controls.Add(main_stu);
					sc.Panel1.Controls.Add(second_stu);
					break;
				case SplitDirection.Left:
					sc.Orientation = Orientation.Vertical;
					sc.Panel2.Controls.Add(main_stu);
					sc.Panel1.Controls.Add(second_stu);
					break;
				case SplitDirection.Right:
					sc.Orientation = Orientation.Vertical;
					sc.Panel1.Controls.Add(main_stu);
					sc.Panel2.Controls.Add(second_stu);
					break;
			}
			if (sc.Orientation == Orientation.Horizontal) {
				sc.SplitterDistance = (sc.Size.Height - sc.SplitterWidth) / 2;
			} else {
				sc.SplitterDistance = (sc.Size.Width - sc.SplitterWidth) / 2;
			}
			main_stu.Dock = DockStyle.Fill;
			second_stu.Dock = DockStyle.Fill;
			main_stu.Visible = true;
			second_stu.Visible = true;
			return sc;
		}
		#endregion

		/// <summary>
		/// 添加一个控件
		/// </summary>
		/// <param name="c"></param>
		/// <param name="before"></param>
		public void addControl(Control c) {
			if (Is_leaf) {
				(MainControl as TabStudio).addControl(c);
			} else {
				Main_studio.addControl(c);
			}
		}
		internal void addControl(Control c, StudioFormHead before) {
			if (Is_leaf) {
				(MainControl as TabStudio).addControl(c, before);
			} else {
				Main_studio.addControl(c, before);
			}
		}
		public void TopMostControl(Control c) {
			var head = (this as IEnumerable<StudioFormHead>).First(h=>h.control == c);
			head.tag_studio.showHeadControl(head);
		}
		public void close() {
			foreach(var studio in Base_studio.studios) {

				if (studio.Parent is IndependentStudioForm) {
					(studio.Parent as IndependentStudioForm).Close();
					Base_studio.studios.Remove(studio);
					this.Dispose();
				}
			}
		}

		#region 拖拽移动控件

		/// <summary>初始化拖拽模块</summary>
		internal void switchShowSplitPanel(bool value) {
			if (value) {
				split_plane.Location = new Point(Size.Width / 2 - 75, Size.Height / 2 - 75);
				split_plane.BringToFront();
				split_plane.Visible = true;
			} else {
				split_plane.Visible = false;
			}
			if (Is_spliter)
				Main_studio?.switchShowSplitPanel(value);
			Second_studio?.switchShowSplitPanel(value);
		}

		/// <summary>初始化拖拽模块</summary>
		public void initializeDrag() {
			split_plane.Visible = false;
			split_plane.UpBTN.DragEnter += split_panel_DragEnter;
			split_plane.DownBTN.DragEnter += split_panel_DragEnter;
			split_plane.LeftBTN.DragEnter += split_panel_DragEnter;
			split_plane.RightBTN.DragEnter += split_panel_DragEnter;
			split_plane.Independent.DragEnter += split_panel_DragEnter;

			split_plane.UpBTN.DragDrop += split_panel_DragDrop;
			split_plane.DownBTN.DragDrop += split_panel_DragDrop;
			split_plane.LeftBTN.DragDrop += split_panel_DragDrop;
			split_plane.RightBTN.DragDrop += split_panel_DragDrop;
			split_plane.Independent.DragDrop += split_panel_DragDrop;
		}
		private void split_panel_DragEnter(object sender, DragEventArgs e) {
			if (e.Data.GetDataPresent(typeof(StudioFormHead))) {
				StudioFormHead from = e.Data.GetData(typeof(StudioFormHead)) as StudioFormHead;
				e.Effect = DragDropEffects.Move;
				Console.WriteLine($"{sender}接受拖放{from}");
			} else {
				e.Effect = DragDropEffects.None;
				Console.WriteLine($"{sender}不接受拖放");
			}
		}
		private void split_panel_DragDrop(object sender, DragEventArgs e) {
			if (e.Effect == DragDropEffects.Move) {
				StudioFormHead from = e.Data.GetData(typeof(StudioFormHead)) as StudioFormHead;
				Studio to;
				if (sender == split_plane.UpBTN) {
					Split(SplitDirection.Top);
					to = Second_studio;
				} else if (sender == split_plane.DownBTN) {
					Split(SplitDirection.Bottom);
					to = Second_studio;
				} else if (sender == split_plane.LeftBTN) {
					Split(SplitDirection.Left);
					to = Second_studio;
				} else if (sender == split_plane.RightBTN) {
					Split(SplitDirection.Right);
					to = Second_studio;
				} else if (sender == split_plane.Independent) {
					to = createSubForm();
				} else {
					throw new Exception("移动窗体到新的视图时发生错误，位置的控件触发了移动。");
				}
				Control c = from.control;
				from.tag_studio.removeControl(from);
				to.addControl(c);
			}
		}
		#endregion

		#region 枚举器
		IEnumerator<Studio> IEnumerable<Studio>.GetEnumerator() {
			yield return this;
			if (Is_spliter) {
				foreach (Studio rev in (IEnumerable<Studio>)Main_studio ) {
					yield return rev;
				}
				foreach (Studio rev in (IEnumerable<Studio>)Second_studio) {
					yield return rev;
				}
			}
		}
		public IEnumerator<StudioFormHead> GetEnumerator() {
			if(Is_leaf) {
				foreach (var rev in (TabStudio)MainControl) {
					yield return rev;
				}
			} else {
				foreach(var rev in Main_studio) {
					yield return rev;
				}
				foreach (var rev in Second_studio) {
					yield return rev;
				}
			}
		}
		IEnumerator IEnumerable.GetEnumerator() {
			throw new NotImplementedException();
		}
		#endregion

		#region Xaml相关程序

		/// <summary>从本Studio输出适合转换为Xaml的实例</summary>
		private ToXaml.SubStudio createXamlObj(){
			var rev = new ToXaml.SubStudio();
			rev.Height = this.Height;
			rev.Width = this.Width;
			if (Is_leaf) {
				rev.Split_distance = -1;
				rev.orientation = Orientation.Horizontal;
				rev.Direacton = SplitDirection.None;
				foreach (var control_head in Tab_studio.Heads) {
					var head = (StudioFormHead)control_head;
					rev.Controls.Add(head.control.get_Head_text());
				}
				rev.Main_studio = null;
				rev.Second_studio = null;
			} else {
				rev.Direacton = Direction;
				rev.orientation = Splitter.Orientation;
				rev.Split_distance = Splitter.SplitterDistance;
				rev.Main_studio = Main_studio.createXamlObj();
				rev.Second_studio = Second_studio.createXamlObj();
			}
			return rev;
		}
		/// <summary>
		/// 从ToXaml.SubStudio加载本工作间的控件
		/// </summary>
		/// <param name="value">记录工作间信息的结构</param>
		/// <param name="dCreateControl">从记录控件的字符串创建控件的委托</param>
		private void loadSubStudioByXaml(ToXaml.SubStudio value, Func<string, Control> dCreateControl) {
			this.Height = value.Height;
			this.Width = value.Width;
			if (value.Direacton == SplitDirection.None) {
				System.Diagnostics.Debug.Assert(value.Split_distance == -1);
				foreach (var control_head in value.Controls) {
					var control = dCreateControl.Invoke(control_head);
					this.addControl(control);
				}
			} else {
				this.Split(value.Direacton);
				Splitter.SplitterDistance = value.Split_distance;
				Splitter.Orientation = value.orientation;
				Main_studio.loadSubStudioByXaml(value.Main_studio, dCreateControl);
				Second_studio.loadSubStudioByXaml(value.Second_studio, dCreateControl);
			}
		}

		/// <summary>
		/// 这个函数可以加载之前保存的，基于ToXaml.Studio的界面。
		/// 推荐在新建的Studio中调用此函数，用来恢复之前保存的界面信息。
		/// </summary>
		/// <param name="xaml_obj">记录工作间和附属窗体的结构。</param>
		/// <param name="dCreateControl">从记录控件的字符串创建控件的委托</param>
		public void loadByXaml(ToXaml.Studio xaml_obj, Func<string, Control> dCreateControl) {
			loadSubStudioByXaml(xaml_obj.Sub_studios[0], dCreateControl);
			for(int i= 1;i< xaml_obj.Sub_studios.Count;i++) {
				Studio other_stuido = createSubForm();
				other_stuido.loadSubStudioByXaml(xaml_obj.Sub_studios[i], dCreateControl);
			}
			return;
		}
		/// <summary>
		/// 从当前的工作间创建 记录工作间和附属窗体的结构。
		/// </summary>
		/// <returns>记录工作间和附属窗体的结构。</returns>
		public ToXaml.Studio ToXaml() {
			var xaml_obj = new ToXaml.Studio();
			foreach (var studio in Base_studio.studios) {
				xaml_obj.Sub_studios.Add(studio.createXamlObj());
			}
			return xaml_obj;
		}







		#endregion


		#region 固定大小按钮

		private void checkButton(Orientation o, ToolStripMenuItem btn) {
			if (!(this.Parent is SplitterPanel) ){
				btn.Enabled = false;
				return;
			}
			SplitContainer sc = (SplitContainer)((Parent as SplitterPanel).Parent);
			if (sc.Orientation!=o) {
				(sc.Parent as Studio).checkButton(o, btn);
				return;
			}
			if (sc.Panel1 == Parent as SplitterPanel) {
				if (sc.FixedPanel == FixedPanel.Panel1) {
					btn.Click += click;
					btn.Enabled = true;
					btn.Checked = true;
					void click(object sender, EventArgs e) {
						sc.FixedPanel = FixedPanel.None;
						//sc.SplitterDistance = o is Orientation.Vertical ? sc.Panel1.Width : sc.Panel1.Height;
					}
				} else {
					btn.Click += click;
					btn.Enabled = true;
					btn.Checked = false;
					void click(object sender, EventArgs e) {
						sc.FixedPanel = FixedPanel.Panel1;
						btn.Click -= click;
					}
				}
			}
			if (sc.Panel2 == Parent as SplitterPanel) {
				if (sc.FixedPanel == FixedPanel.Panel2) {
					btn.Click += click;
					btn.Enabled = true;
					btn.Checked = true;
					void click(object sender, EventArgs e) {
						sc.FixedPanel = FixedPanel.None;
						//sc.SplitterDistance = o is Orientation.Vertical ? sc.Panel1.Width : sc.Panel1.Height;
					}
				} else {
					btn.Click += click;
					btn.Enabled = true;
					btn.Checked = false;
					void click(object sender, EventArgs e) {
						sc.FixedPanel = FixedPanel.Panel2;
					}
				}
			}
		} 
		private void FixedSizeCSM_Opening(object sender, CancelEventArgs e) {
			checkButton(Orientation.Vertical, FixVerticalBtn);
			checkButton(Orientation.Horizontal, FixHorizontalBtn);
		}
#endregion
	}
	public enum SplitDirection {
		None,Left, Right, Top, Bottom
	}


}
